#include "user_global.h"
#include "modbus.h"
#include "user_device.h"
#include <string.h>
#include <stdio.h>
#include <math.h>

#define SCANBAR_OK                      0
#define SCANBAR_CHECKSUM_ERROR          1
#define SCANBAR_TIMEOUT                 2

enum {
    BARCODE_TYPE_NORMAL = 0,
    BARCODE_TYPE_POS = 1,
    BARCODE_TYPE_RACKID = 2
};

ulong scanbar_wait_timestamp = 0;           // 等待开始时间
uchar scanbar_read_result = SCANBAR_OK;
bit scanbar_actived = 0;                     // 条码扫描正在运行
uchar scanbar_action = 2;                    // 条码扫描正在运行
uchar barcode_scanner_commit_errs = 0;       // 与条码扫描器通讯错误次数

SCANBAR mbar;                       // 条码扫描控制对象
bit check_reply = 0;                // 指令代码,等待设备回复校验
uchar check_type = 0;               // 条码接收类型

bit scanbar_need_delay_off = 0;                               // 条码扫描需要延时关闭
bit scanbar_need_delay_on = 0;                                // 条码扫描需要延时打开
ulong scanbar_keep_on_timestamp = 0;                          // 扫码器打开保持时间计数
ulong scanbar_keep_off_timestamp = 0;                         // 扫码器关闭保持时间计数
#define SCANBAR_KEEP_ON_TIME  US_TO_TICK_UL(25000000)         // 扫码器打开保持时间
#define SCANBAR_KEEP_OFF_TIME US_TO_TICK_UL(500000)           // 扫码器关闭保持时间

void Scanbar_SendMessage(uchar *ptr, uchar len);

#if defined(USE_AUTO_TRIGGER) || defined(PRODUCT_DEBUG)

const SCANBAR_CHECK scanbar_check[10] = {
    {{4},{0x02,0x3F,0x0D,0x0A}},
    {{6},{0x02,0x50,0x53,0x30,0x0D,0x0A}},   // "PS0"
};

#ifdef PRODUCT_DEBUG
ulong slot_stamp[4] = {0};                  // 样本架在槽内输入到位运行的时间戳
#endif

// uart1接收到了帧结束
bit Uart1_FrameEnded()
{
    ulong t;

    t = uart1_timestamp_long;
    return SystemTick() - t >= MAX_BYTE_TO_BYTE_DELAY;
}


// 读取数据帧
void Scanbar_Read()
{
    uchar i;
    if (uart1_rx_len == 0)
    {
        if (SystemTick() - scanbar_wait_timestamp >= TICK_TIMEOUT)
        {
            uart1_rx_pending = 0;
            scanbar_read_result = SCANBAR_TIMEOUT;
            scanbar_wait_timestamp = SystemTick();
        }
    }
    else
    {
        if (uart1_rx_len < 2)
        {
            if (Uart1_FrameEnded())
            {
                uart1_rx_pending = 0;
                scanbar_read_result = SCANBAR_TIMEOUT;
            }
        }
        else
        {

            if((uart1_rx_buf[uart1_rx_len - 2] == CR &&
                uart1_rx_buf[uart1_rx_len - 1] == LF))
            {
                scanbar_read_result = SCANBAR_OK;
                for(i = 0; i < scanbar_check[check_type].len; ++i)
                {
                    if(uart1_rx_buf[i] != scanbar_check[check_type].buf[i])
                    {
                        scanbar_read_result = SCANBAR_CHECKSUM_ERROR;
                        break;
                    }

                }
                uart1_rx_pending = 0;
            }

        }
        scanbar_wait_timestamp = SystemTick();
    }
}
#endif

#ifdef USE_AUTO_TRIGGER
// 给条码模块发送指令, 并等待回应
bit Scanbar_Exchange_Message(uchar *ptr, uchar len)
{
    uchar retry_time;

    for(retry_time=0; retry_time < 2; ++retry_time)
    {
        Scanbar_SendMessage(ptr, len);

        // 等待发送完成
        while(uart1_tx_pending)
            Main_Loop();

        scanbar_wait_timestamp = SystemTick();

        // 等待接收完成
        while(uart1_rx_pending)
        {
            Scanbar_Read();
            Main_Loop();
        }

        if (scanbar_read_result == SCANBAR_OK)
        {
            barcode_scanner_not_found = 0;
            barcode_scanner_commit_errs = 0;
            return 1;
        }
        else {
            if(++barcode_scanner_commit_errs > 20)
                barcode_scanner_not_found = 1;
        }

    }

    return 0;
}
#endif

// 计算检验和, 开始发送
void Scanbar_SendMessage(uchar *ptr, uchar len)
{
    uchar i;

    if (ptr != uart1_tx_buf)
    {
        for(i=0; i<len; ++i)
            uart1_tx_buf[i] = ptr[i];
    }

    uart1_tx_len = len;

    Uart1_Send();
}


void Scan_Code(bit enable)
{
    scanbar_action = enable;
    Start_Beep(0);
}

// 重置样本状态
void Reset_Sample_State(uchar sample_index)
{
    uchar index;
    for(index = 0; index < (MAX_SAMPLE_COUNTS_BY_UNIT + MAX_RACKID_COUNTS_BY_UNIT); ++index)
    {
        memset(ro_word.barcodes[index], 0, MAX_BAR_LEN);
    }

#ifdef PRODUCT_DEBUG
    for(i = 0; i <= MAX_POS_CODE_VALUE; ++i)
    {
        index = i + sample_index * (MAX_POS_CODE_VALUE+1);
        poscodes[index][0] = 0;
    }

    slot_duration[sample_index] = 0;
#endif
}

void Active_Scan()
{
#ifdef BCL95
#ifdef USE_AUTO_TRIGGER
    uart1_tx_ptr = uart1_tx_buf;
    *uart1_tx_ptr++ = STX;
    *uart1_tx_ptr++ = 0x50;
    *uart1_tx_ptr++ = 0x54;
    *uart1_tx_ptr++ = 0x30;
    *uart1_tx_ptr++ = 0x30;
    *uart1_tx_ptr++ = 0x32;
    *uart1_tx_ptr++ = 0x30;
    *uart1_tx_ptr++ = 0x33;
    *uart1_tx_ptr++ = 0x34;
    *uart1_tx_ptr++ = 0x30;
    *uart1_tx_ptr++ = 0x31;
    *uart1_tx_ptr++ = CR;
    *uart1_tx_ptr++ = LF;
    check_reply = 1;
    check_type = 1;
    Scanbar_Exchange_Message(uart1_tx_buf, uart1_tx_ptr - uart1_tx_buf);
    check_reply = 0;
#else
    uart1_tx_ptr = uart1_tx_buf;
    *uart1_tx_ptr++ = STX;
    *uart1_tx_ptr++ = 0x43;
    *uart1_tx_ptr++ = 0x2B;
    *uart1_tx_ptr++ = CR;
    *uart1_tx_ptr++ = LF;

     /*uart1_tx_ptr = uart1_tx_buf;
     *uart1_tx_ptr++ = 0x4C;
     *uart1_tx_ptr++ = 0x4F;
     *uart1_tx_ptr++ = 0x4E;
     *uart1_tx_ptr++ = CR;*/
    Scanbar_SendMessage(uart1_tx_buf, uart1_tx_ptr - uart1_tx_buf);
#endif
#else
    IO_Set(IO_NTRIG);
#endif

    scanbar_actived = 1;
    scanbar_need_delay_off = 0;
    scanbar_need_delay_on = 0;
    mbar.state = SCANBAR_RUNNING;
}

// 启动条码模块扫描
void Start_Scan(uchar sample_index)
{
    Active_Scan();

    mbar.index = 0;
    mbar.read = 0;
    mbar.write = 0;
    mbar.lasttype = 255;
    mbar.barcount = 0;
    mbar.sample_index = sample_index;
    Reset_Sample_State(sample_index);
#ifdef SCAN_FROM_SMALL_TO_LARGE
    mbar.recent_pos = 0;
    mbar.last_pos = 0;
#else
    mbar.recent_pos = MAX_SAMPLE_COUNTS_BY_UNIT;
    mbar.last_pos = MAX_SAMPLE_COUNTS_BY_UNIT;
#endif
    mbar.spare_index = 0;

#ifdef PRODUCT_DEBUG
    slot_stamp[sample_index] = SystemTick();
#endif
    ro_word.barCount = 0;
   // beep_mode = BEEP_INFO;
}

#ifdef PRODUCT_DEBUG
// 关闭重复输出的功能
bit Output_Diff_Only()
{
    uchar retry_time = 0;
    uart1_tx_ptr = uart1_tx_buf;
    *uart1_tx_ptr++ = STX;
    *uart1_tx_ptr++ = 0x50;
    *uart1_tx_ptr++ = 0x54;
    *uart1_tx_ptr++ = 0x30;
    *uart1_tx_ptr++ = 0x30;
    *uart1_tx_ptr++ = 0x32;
    *uart1_tx_ptr++ = 0x30;
    *uart1_tx_ptr++ = 0x38;
    *uart1_tx_ptr++ = 0x36;
    *uart1_tx_ptr++ = 0x41;
    *uart1_tx_ptr++ = 0x30;
    *uart1_tx_ptr++ = CR;
    *uart1_tx_ptr++ = LF;
    check_reply = 1;
    check_type = 1;

    for(retry_time=0; retry_time < 5; ++retry_time)
    {
        Scanbar_SendMessage(uart1_tx_buf, uart1_tx_ptr - uart1_tx_buf);

        scanbar_wait_timestamp = SystemTick();
        // 等待发送完成
        while(uart1_tx_pending)
        {
            Main_Loop();
            if (SystemTick() - scanbar_wait_timestamp >= TICK_TIMEOUT)
                break;
        }

        scanbar_wait_timestamp = SystemTick();

        // 等待接收完成
        while(uart1_rx_pending)
        {
            Main_Loop();
            Scanbar_Read();
        }

        if (scanbar_read_result == SCANBAR_OK)
            return 1;
    }
    return 0;
}
#endif
// 停止条码扫描
void Stop_Scan(uchar sample_index)
{
#ifdef BCL95
#ifdef USE_AUTO_TRIGGER
    uart1_tx_ptr = uart1_tx_buf;
    *uart1_tx_ptr++ = STX;
    *uart1_tx_ptr++ = 0x50;
    *uart1_tx_ptr++ = 0x54;
    *uart1_tx_ptr++ = 0x30;
    *uart1_tx_ptr++ = 0x30;
    *uart1_tx_ptr++ = 0x32;
    *uart1_tx_ptr++ = 0x30;
    *uart1_tx_ptr++ = 0x33;
    *uart1_tx_ptr++ = 0x34;
    *uart1_tx_ptr++ = 0x30;
    *uart1_tx_ptr++ = 0x30;
    *uart1_tx_ptr++ = CR;
    *uart1_tx_ptr++ = LF;
    check_reply = 1;
    check_type = 1;
    Scanbar_Exchange_Message(uart1_tx_buf, uart1_tx_ptr - uart1_tx_buf);
#else
     uart1_tx_ptr = uart1_tx_buf;
     *uart1_tx_ptr++ = STX;
     *uart1_tx_ptr++ = 0x43;
     *uart1_tx_ptr++ = 0x2D;
     *uart1_tx_ptr++ = CR;
     *uart1_tx_ptr++ = LF;

     /*uart1_tx_ptr = uart1_tx_buf;
     *uart1_tx_ptr++ = 0x4C;
     *uart1_tx_ptr++ = 0x4F;
     *uart1_tx_ptr++ = 0x46;
     *uart1_tx_ptr++ = 0x46;
     *uart1_tx_ptr++ = CR;*/
     check_reply = 1;
     check_type = 0;
     Scanbar_SendMessage(uart1_tx_buf, uart1_tx_ptr - uart1_tx_buf);
#endif
#else
    IO_Reset(IO_NTRIG);
#endif
    sample_index = sample_index;
    check_reply = 0;
    mbar.state = SCANBAR_IDLE;
    scanbar_keep_on_timestamp = SystemTick();
    scanbar_actived = 0;
    scanbar_need_delay_on = 0;
    scanbar_need_delay_off = 0;
}

unsigned char AsciiToHex(char c)
{
    if ('0' <= c && c <= '9')
        return c-'0';
    else if ('A' <= c && c <= 'F')
        return c-'A'+0x0A;
    else if ('a' <= c && c <= 'f')
        return c-'a'+0x0A;
    else
        return 0;
}

// 读取位置码位置，返回位置
unsigned char Read_Barpos(char *barcode)
{
    unsigned char index = 0;
    index = (mbar.sample_index * MAX_SAMPLE_COUNTS_BY_UNIT + AsciiToHex((char)barcode[2]) * 10 + AsciiToHex((char)barcode[3]) );
    return index <= MAX_SAMPLE_COUNTS_BY_UNIT ? index : MAX_SAMPLE_COUNTS_BY_UNIT;
}


// 识别条码类型 1: 位置码 ; 0：样本码
uchar Identify_Type(char *barcode, uchar len)
{
    uchar type = 0;
    ushort index = 0;
    // 位置码 :标识,内容,长度判断
    if(barcode[1] == '#' && barcode[4] == '#')
    {
        index = AsciiToHex((char)barcode[2]) * 10 + AsciiToHex((char)barcode[3]);
        if(index <= MAX_POS_CODE_VALUE-1 && len == POS_CODE_LEN)
        {
            type = 1;
            memcpy(ro_word.poscodes[index], &barcode[1], 4);
#ifdef PRODUCT_DEBUG
            ++number_of_pos[mbar.sample_index*(MAX_POS_CODE_VALUE+1) + index];
            memcpy(poscodes[mbar.sample_index*(MAX_POS_CODE_VALUE+1) + index], &barcode[1], 4);
#endif
        }
    }
    // 试管架id :标识,内容,长度判断
    if(barcode[1] == '#' && barcode[5] == '#')
    {
        index = AsciiToHex((char)barcode[2]) * 100 + AsciiToHex((char)barcode[3])*10 + AsciiToHex((char)barcode[4]);
        if(index <= MAX_RACKID_CODE_VALUE && len == RACKID_CODE_MAX_LEN)
        {
            type = 2;
        }
    }
    return type;
}
unsigned char Tube_Number_Len_Check(unsigned char len,unsigned char checkLen)
{
    unsigned char result;
    if(checkLen == 0)
    {
         result = 1;
    }
    else if(len >= checkLen )
    {
         result = 1;
    }
    else
    {
         result = 0;
    }
    return result;
}

#ifdef SCAN_FROM_SMALL_TO_LARGE
// 条码分置
uchar Arrange_Barcode(char *barcode, uchar len)
{
    uchar i;
    uchar type;
    uchar Expect_Min_Len;
    Expect_Min_Len = (uchar)rw_word.app_args[0];
    if(len < 4)         //  含STX CR LF 0x00(null)
        return 255;

    type = Identify_Type(barcode,len);
    if(type)          // 位置码
    {
        mbar.last_pos = mbar.recent_pos;
        mbar.recent_pos = (type == 1 ? Read_Barpos(barcode) : MAX_POS_CODE_VALUE);

        // 拷贝试管架条码id
        if(type == BARCODE_TYPE_RACKID)
        {
            memcpy(ro_word.barcodes[5], &barcode[2], RACKID_CODE_LEN);
            ro_word.barcodes[5][RACKID_CODE_LEN] = 0x00;
        }

        // 上一次也是位置码
        if(mbar.lasttype == 0)
        {
            if(mbar.recent_pos - mbar.last_pos > 1)
            {
                Start_Beep(BEEP_ERR);
            }
            else
            {
                Start_Beep(BEEP_WARNING);
            }
        }
        else
        {
            // 位置码连续
            if(mbar.recent_pos - mbar.last_pos == 1)
            {
                // 样本码属于该位置
                if(mbar.sample_pos == mbar.last_pos)
                {
                    memcpy(ro_word.barcodes[mbar.last_pos], mbar.spare_barcode[0], strlen(mbar.spare_barcode[0]));
                    ro_word.barcodes[mbar.last_pos][strlen(mbar.spare_barcode[0])] = 0x00;
                }
            }
            // 位置码不连续 且有多余读取的样本码
            else if(mbar.spare_index && (mbar.recent_pos > mbar.last_pos + 1))
            {
                // 未扫到的多余的位置码和多余的样本码数量相同
                if(mbar.recent_pos - mbar.last_pos == mbar.spare_index)
                {
                    for(i = 0 ; i < mbar.spare_index; ++i)
                    {
                        memcpy(ro_word.barcodes[mbar.last_pos + i], mbar.spare_barcode[i], strlen(mbar.spare_barcode[i]));
                        ro_word.barcodes[mbar.last_pos + i][strlen(mbar.spare_barcode[i])] = 0x00;
                        mbar.spare_barcode[i][0] = 0x00;
                    }
                }

            }
        }
        mbar.lasttype = 0;
        mbar.spare_index = 0;
    }
    else if(Tube_Number_Len_Check(len-4,Expect_Min_Len))                                    // 样本码
    {
        // 上一次也是样本码
        if(mbar.lasttype == 1)
        {
            Start_Beep(BEEP_ERR);
            memcpy(mbar.spare_barcode[mbar.spare_index], &barcode[1], len - 3);
            mbar.spare_barcode[mbar.spare_index][len - 4 ] = 0x00;
            mbar.spare_index = ++mbar.spare_index % MAX_BAR_NUMBER;
        }
        else {

            memcpy(mbar.spare_barcode[0], &barcode[1], len - 3);
            mbar.spare_barcode[0][len - 4 ] = 0x00;
            mbar.spare_index = 1;
            mbar.sample_pos = mbar.recent_pos;
        }
        mbar.lasttype = 1;
    }
    memcpy(ro_word.recent_barcode, &barcode[1], len - 3);
    ro_word.recent_barcode[len - 4] = 0x00;
    return  mbar.recent_pos;

}
#else
// 条码分置
uchar Arrange_Barcode(char *barcode,uchar len)
{
    uchar i,j;
    if(len < 4)  //  含STX CR LF 0x00(null)
        return 255;

    if(Identify_Type(barcode,len))          // 位置码
    {
        mbar.last_pos = mbar.recent_pos;
        mbar.recent_pos = Read_Barpos(barcode);

        // 上一次也是位置码
        if(mbar.lasttype == 0)
        {
            if(fabs((char)mbar.last_pos - (char)mbar.recent_pos > 1))
            {
//                beep_mode = BEEP_ERR;
            }
            else
            {
//                beep_mode = BEEP_WARNING;
                if(mbar.last_pos - mbar.recent_pos == 1)
                {
                    //Write_Reg_Bit(&ro_bit_2,mbar.recent_pos,0);
                    ro_word.barcodes[mbar.recent_pos][0] = 0;
                }
            }
        }
        else
        {
            // 位置码连续
            if(mbar.last_pos - mbar.recent_pos == 1)
            {
                // 样本码属于该位置
                if(mbar.sample_pos == mbar.last_pos)
                {
                    memcpy(ro_word.barcodes[mbar.recent_pos],mbar.spare_barcode[0],strlen(mbar.spare_barcode[0]));
                    ro_word.barcodes[mbar.recent_pos][strlen(mbar.spare_barcode[0])] = 0x00;
                    // ++number_of_sample[mbar.recent_pos];
                    // Write_Reg_Bit(&ro_bit_2,mbar.recent_pos,1);
                }
            }
            // 位置码不连续 且有多余读取的样本码
            else if(mbar.spare_index && (mbar.recent_pos < mbar.last_pos - 1))
            {
                // 未扫到的多余的位置码和多余的样本码数量相同
                if(mbar.last_pos - mbar.recent_pos == mbar.spare_index)
                {
                    for(i = 0 ; i < mbar.spare_index; ++i)
                    {
                        j = mbar.recent_pos + mbar.spare_index - 1 -i;
                        memcpy(ro_word.barcodes[j],mbar.spare_barcode[i],strlen(mbar.spare_barcode[i]));
                        ro_word.barcodes[j][strlen(mbar.spare_barcode[i])] = 0x00;
                        //++number_of_sample[j];
                        //Write_Reg_Bit(&ro_bit_2,j,1);
                        mbar.spare_barcode[i][0] = 0x00;
                    }
                }

            }
        }
        mbar.lasttype = 0;
        mbar.spare_index = 0;
    }
    else                                    // 样本码
    {
        // 上一次也是样本码
        if(mbar.lasttype == 1)
        {
//            beep_mode = BEEP_ERR;
            memcpy(mbar.spare_barcode[mbar.spare_index],&barcode[1],len - 3);
            mbar.spare_barcode[mbar.spare_index][len - 4 ] = 0x00;
            mbar.spare_index = ++mbar.spare_index % MAX_BAR_NUMBER;
        }
        else {

            memcpy(mbar.spare_barcode[0],&barcode[1],len - 3);
            mbar.spare_barcode[0][len - 4 ] = 0x00;
            mbar.spare_index = 1;
            mbar.sample_pos = mbar.recent_pos;
        }
        mbar.lasttype = 1;

    }
    memcpy(ro_word.recent_barcode,&barcode[1],len - 3);
    ro_word.recent_barcode[len - 4] = 0x00;
    return  mbar.recent_pos;
}
#endif

SCAN_CNTRL scnt;

void Append_Bar(char * bar,uchar len)
{
    if ((mbar.write + 1) % MAX_BAR_NUMBER != mbar.read)    //Have new data.
    {
        mbar.barlen[mbar.write] = len;
        memcpy(mbar.barcode[mbar.write], bar, len);
        mbar.write = (mbar.write + 1) % MAX_BAR_NUMBER;
    }
}

// 启动关闭条码扫描
void Scanbar_Trigger()
{
    switch(scanbar_action)
    {
    case 0:   // 关闭
        Stop_Scan(0);
        scanbar_action = 2;
        break;
    case 1:   // 打开
        Start_Scan(0);
        scanbar_action = 2;
        break;
    case 2:
        break;
    }
}

uchar Mbar_Count()
{
    return mbar.barcount;
}

// 读取到了最后的位置码
uchar Rack_Scan_Finished()
{
#ifdef SCAN_FROM_SMALL_TO_LARGE
    return mbar.recent_pos == MAX_POS_CODE_VALUE;
#else
    return mbar.recent_pos == 0;
#endif
}

// 条码处理
void Process_Scanbar()
{
    // 读取缓存条码
    if(mbar.read != mbar.write )
    {
        Arrange_Barcode(mbar.barcode[mbar.read], mbar.barlen[mbar.read]);
        mbar.read = (mbar.read + 1) % MAX_BAR_NUMBER;
        ++mbar.barcount;
    }

    Scanbar_Trigger();
}
